//
// Created by lqk on 2022/1/29.
//
#ifdef __linux__
#include <sys/timerfd.h>
#endif
#include <cmath>
#include <unistd.h>
#include "PeriodicTask.h"

PeriodicTask::PeriodicTask(PeriodicTaskManager *taskManager,const float& period,const std::string& name)
:m_period(period),m_name(name){
    taskManager->AddTask(this);
}

void PeriodicTask::Start() {
    if(m_isRunning){
        std::cout<<"[PeriodicTask]"<<m_name<<" is already runnning"<<std::endl;
        return;
    }
    Init();
    m_isRunning=true;
    m_thread=std::thread(&PeriodicTask::LoopFunction,this);

}

void PeriodicTask::Stop() {
    if(!m_isRunning){
        std::cout<<"[PeriodicTask]"<<m_name<<" is already not running"<<std::endl;
        return;
    }
    m_isRunning=false;
    std::cout<<"[PeriodicTask] Waiting for "<<m_name<<"to stop"<<std::endl;
    m_thread.join();
    std::cout<<"[PeriodicTask] Done!"<<std::endl;
    CleanUp();
}

void PeriodicTask::PrintStatus() {

}

void PeriodicTask::LoopFunction() {
#ifdef __linux__
    auto timerFd = timerfd_create(CLOCK_MONOTONIC,0);
#endif
    int seconds = (int)m_period;
    int nanoseconds = (int)(1e9*std::fmod(m_period,1.f));

#ifdef __linux__
    itimerspec timerSpec;
    timerSpec.it_interval.tv_sec = seconds;
    timerSpec.it_value.tv_sec = seconds;
    timerSpec.it_value.tv_nsec = nanoseconds;
    timerSpec.it_interval.tv_nsec = nanoseconds;
    timerfd_settime(timerFd,0,&timerSpec, nullptr);
#endif
    unsigned long long missed = 0;

    while(m_isRunning){
       RunOnce();
#ifdef __linux__
       int m = read(timerFd,&missed,sizeof(missed));
       (void)m;
#endif
    }
    std::cout<<"[PeriodicTask]"<<m_name<<" has stopped!"<<std::endl;

}